use std::{rc::Rc, cell::RefCell};

use crate::{
    instructions::{
        base::{Instruction, BytecodeReader}, 
        loads::{ILOAD, LLOAD, FLOAD, DLOAD, ALOAD}, 
        stores::{ISTORE, LSTORE, FSTORE, DSTORE, ASTORE},
        math::IINC
    }, 
    rtda::Frame
};



// Extend local variable index by additional bytes
#[derive(Debug, Default)]
pub struct WIDE {
    modified_instruction: Option<Box<dyn Instruction>>
}

impl Instruction for WIDE {
    fn fetch_operands(&mut self, reader: &mut BytecodeReader) {
        let opcode = reader.read_u8();
        match opcode {
            0x15 => {
                let mut inst = ILOAD::default();
                inst.set_index(reader.read_u16() as usize);
                self.modified_instruction = Some(Box::new(inst));
            },
            0x16 => {
                let mut inst = LLOAD::default();
                inst.set_index(reader.read_u16() as usize);
                self.modified_instruction = Some(Box::new(inst));
            },
            0x17 => {
                let mut inst = FLOAD::default();
                inst.set_index(reader.read_u16() as usize);
                self.modified_instruction = Some(Box::new(inst));
            },
            0x18 => {
                let mut inst = DLOAD::default();
                inst.set_index(reader.read_u16() as usize);
                self.modified_instruction = Some(Box::new(inst));
            },
            0x19 => {
                let mut inst = ALOAD::default();
                inst.set_index(reader.read_u16() as usize);
                self.modified_instruction = Some(Box::new(inst));
            },
            0x36 => {
                let mut inst = ISTORE::default();
                inst.set_index(reader.read_u16() as usize);
                self.modified_instruction = Some(Box::new(inst));
            },
            0x37 => {
                let mut inst = LSTORE::default();
                inst.set_index(reader.read_u16() as usize);
                self.modified_instruction = Some(Box::new(inst));
            },
            0x38 => {
                let mut inst = FSTORE::default();
                inst.set_index(reader.read_u16() as usize);
                self.modified_instruction = Some(Box::new(inst));
            },
            0x39 => {
                let mut inst = DSTORE::default();
                inst.set_index(reader.read_u16() as usize);
                self.modified_instruction = Some(Box::new(inst));
            },
            0x3a => {
                let mut inst = ASTORE::default();
                inst.set_index(reader.read_u16() as usize);
                self.modified_instruction = Some(Box::new(inst));
            },
            0x84 => {
                let mut inst = IINC::default();
                inst.set_index(reader.read_u16() as usize);
                inst.set_count(reader.read_i16() as i32);
                self.modified_instruction = Some(Box::new(inst));
            },
            0xa9 => { // ret
                panic!("Unsupported opcode: 0xa9!");
            }
            _ => ()
        }
    }

    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        self.modified_instruction.as_mut().unwrap().execute(frame);
    }
}